#pragma once

#include "imageclip.h"
#include "panel.h"

typedef void (*ButtonCallbackFunction)(void * a_param);

class Button : public Panel
{
protected:
	/** is the button being pressed (but not yet released) */
	bool m_pressed;
	/** is the mouse is over the cursor */
	bool m_mouseOver;
	/** if the button has an on AND off state */
	bool m_canBeToggled;
	/** whether or not the button is active */
	bool m_isOn;
	/** what to execute when this button is pressed (if anything) */
	ButtonCallbackFunction m_function;
	/** what parameter to execute the function with */
	void * m_functionData;
public:
	void copy(const Button & b)
	{
		Panel::copy(b);
		m_pressed = b.m_pressed;
		m_mouseOver = b.m_mouseOver;
		m_canBeToggled = b.m_canBeToggled;
		m_isOn = b.m_isOn;
		m_function = b.m_function;
		m_functionData = b.m_functionData;
		setDirty(0);
	}
	Button():m_function(0),m_functionData(0),m_mouseOver(0),m_pressed(0),m_canBeToggled(0),m_isOn(0){}
	void setAction(ButtonCallbackFunction a_function, void * a_functionData)
	{
		m_function = a_function;
		m_functionData = a_functionData;
	}

	void handlePress()
	{
		if(m_canBeToggled)
		{
			setOn(!m_isOn);
		}
		if(m_function)
		{
			m_function(m_functionData);
		}
	}

	void setOn(const bool & a_isOn){m_isOn=a_isOn;}

	void setToggleable(const bool & a_toggleable)
	{
		m_canBeToggled = a_toggleable;
		if(!m_canBeToggled)
		{
			setOn(false);
		}
	}

	/**
	 * @return if the button is in the on state. 
	 * @note: buttons that cannot be toggled will never be in the on state
	 */
	inline bool isOn()
	{
		return m_isOn;
	}

	/** @return true if this button has an on AND off state */
	inline bool isToggleable()
	{
		return m_canBeToggled;
	}

	/** @return true if the mouse is over this button */
	bool isOver(){return m_mouseOver;}

	/** @return true if the mouse is being pressed, but not yet released */
	bool isPressed(){return m_pressed;}

	/** @return true if the given mouse coordinate would be in the button's area */
	bool isMouseIsInButton(const SPoint & a_mouse)
	{
		return getArea()->contains(a_mouse);
	}

	virtual bool handleEvent(const SDL_Event & e)
	{
		bool wasMouseOver = m_mouseOver;
		bool handled = false;
		bool dirty = false;
		switch(e.type)
		{
		case SDL_MOUSEMOTION:
			m_mouseOver = isMouseIsInButton(SPoint(e.motion.x, e.motion.y));
			break;
		case SDL_MOUSEBUTTONDOWN:
			m_mouseOver = isMouseIsInButton(SPoint(e.button.x, e.button.y));
			switch(e.button.button)
			{
			case SDL_BUTTON_LEFT:
				dirty = true;
				m_pressed = m_mouseOver;
				break;
			}
			break;
		case SDL_MOUSEBUTTONUP:
			m_mouseOver = isMouseIsInButton(SPoint(e.button.x, e.button.y));
			switch(e.button.button)
			{
			case SDL_BUTTON_LEFT:
				dirty = true;
				if(m_pressed && m_mouseOver)
				{
					handlePress();
					handled = true;
				}
				m_pressed = false;
				break;
			}
			break;
		}
		dirty |= wasMouseOver != m_mouseOver;
		if(dirty)
			setDirty(0);
		return handled;
	}
};